package template

import (
	"context"
	"encoding/json"
	v1 "go_muban/api/template/v1"
	"go_muban/internal/dao"
	"go_muban/internal/model"
	"go_muban/internal/model/do"
	"go_muban/internal/model/entity"
	"go_muban/internal/service"
	"strconv"

	"github.com/gogf/gf/v2/container/garray"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/gconv"
)

// 实现 template 服务接口
type sTemplate struct{}

// 注册服务实例
func init() {
	service.RegisterTemplate(New())
}

// New 创建服务实例
func New() service.ITemplate {
	return &sTemplate{}
}

// GetList 获取模板列表
func (s *sTemplate) GetList(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error) {
	// 查询模板列表
	templates, total, err := s.GetTemplateList(ctx, req)
	if err != nil {
		return nil, err
	}

	// 计算分页
	pageSize := int64(req.PageSize)
	pageCount := (int64(total) + pageSize - 1) / pageSize
	pages := garray.NewIntArray()
	for i := 1; i <= int(pageCount); i++ {
		pages.Append(i)
	}

	// 查询分类列表 - 使用g.List和g.Map
	// 查询分类列表 - 从数据库获取
	var categories []entity.MbCategories
	err = dao.MbCategories.Ctx(ctx).
		Fields("id", "title").
		Where("is_show", 1).
		Order("title ASC").
		Scan(&categories)
	if err != nil {
		return nil, err
	}

	// 构建查询字符串
	queryParams := ""
	if req.Category > 0 {
		queryParams += "category=" + strconv.Itoa(req.Category)
	}
	if req.Tag > 0 {
		if queryParams != "" {
			queryParams += "&"
		}
		queryParams += "tag=" + strconv.Itoa(req.Tag)
	}

	// 如果有标签ID，查询标签名称
	tags := make([]entity.MbTags, 0)
	if req.Tag > 0 {
		var tag *entity.MbTags
		err = dao.MbTags.Ctx(ctx).
			Where("id", req.Tag).
			Fields("title").
			Scan(&tag)
		if err != nil {
			return nil, err
		}

		if tag != nil {
			tags = append(tags, *tag)
		}
	}

	// 返回结果
	res = &v1.ListRes{
		Templates:  templates,
		Categories: categories,
		Tags:       tags,
		Pagination: g.Map{
			"total":   pageCount,
			"current": req.Page,
			"pages":   pages.Slice(),
			"query":   queryParams,
		},
		QueryParams: queryParams,
	}
	return
}

// GetDetail 获取模板详情
func (s *sTemplate) GetDetail(ctx context.Context, req *v1.DetailReq) (res *v1.DetailRes, err error) {
	// 查询模板详情
	id, err := strconv.Atoi(req.Id)
	if err != nil {
		return nil, err
	}

	template, err := s.GetTemplateDetail(ctx, id)
	if err != nil {
		return nil, err
	}

	if template == nil {
		return nil, gerror.New("模板不存在")
	}

	// 查询相关模板
	relatedTemplates, _ := s.GetRelatedTemplates(ctx, template, 4)

	// 使用日志记录标签数据，便于调试
	g.Log().Debug(ctx, "模板标签数据：", template.Tags)

	// 返回结果
	res = &v1.DetailRes{
		Template:         template,
		RelatedTemplates: relatedTemplates,
	}
	return
}

// GetTemplateList 获取模板列表
func (s *sTemplate) GetTemplateList(ctx context.Context, req *v1.ListReq) ([]model.MbTemplateItem, int, error) {
	// 构建查询条件
	query := dao.MbTemplates.Ctx(ctx)
	if req.Category > 0 {
		query = query.Where("category_id", req.Category)
	}
	if req.Tag > 0 {
		// 将 tags 作为 JSON 数组处理，查询包含指定标签 ID 的记录
		query = query.Where("JSON_CONTAINS(tags, ?)", strconv.Itoa(req.Tag))
	}
	// 只查询2020年之后的数据
	query = query.Where("updated >= ?", "2016-01-01 00:00:00")
	// 添加排序条件
	query = query.OrderDesc("updated")

	// 查询数据
	result, err := query.Page(req.Page, req.PageSize).OrderDesc("updated").All()
	if err != nil {
		return nil, 0, err
	}
	// 查询总数
	total, err := query.Count()
	if err != nil {
		return nil, 0, err
	}

	// 转换为模板列表
	templates := make([]model.MbTemplateItem, 0)
	if err = gconv.Scan(result, &templates); err != nil {
		return nil, 0, err
	}

	return templates, total, nil
}

// GetTemplateDetail 获取模板详情
func (s *sTemplate) GetTemplateDetail(ctx context.Context, id int) (*model.MBDetail, error) {
	// 查询模板详情，使用With特性关联查询分类和标签
	result, err := dao.MbTemplates.Ctx(ctx).
		Where("id", id).
		One()
	if err != nil {
		return nil, err
	}

	if result.IsEmpty() {
		return nil, nil
	}

	mbTemplate := model.MbTemplateItem{}

	// 将结果转换为模板对象
	if err = gconv.Scan(result, &mbTemplate); err != nil {
		return nil, err
	}

	// 转换为详情对象
	detail := &model.MBDetail{
		Id:       mbTemplate.Id,
		SId:      mbTemplate.SId,
		Title:    mbTemplate.Title,
		Thumb:    mbTemplate.Thumb,
		Images:   mbTemplate.Images,
		Preview:  mbTemplate.Preview,
		Updated:  mbTemplate.Updated.String(),
		FileSize: mbTemplate.FileSize,
		Download: mbTemplate.Download,
		Desc:     mbTemplate.Desc,
		Origin:   mbTemplate.Origin,
	}

	// 如果有标签ID，查询对应的标签信息
	if len(mbTemplate.Tags) > 0 {
		// 构建ID查询条件
		tagIds := garray.NewIntArrayFrom(mbTemplate.Tags)

		// 记录日志
		g.Log().Debug(ctx, "模板标签IDs：", tagIds.Slice())

		// 查询标签
		tagResult, err := dao.MbTags.Ctx(ctx).
			WhereIn("id", tagIds.Slice()).
			Order("title ASC").
			All()
		if err != nil {
			return nil, err
		}

		// 将查询结果转换为标签列表
		tags := make([]model.EnHrefItem, 0)
		if err = gconv.Scan(tagResult, &tags); err != nil {
			return nil, err
		}

		// 记录日志
		g.Log().Debug(ctx, "查询到的标签数量：", len(tags))

		// 设置详情对象的标签
		detail.Tags = tags
	} else {
		// 记录没有标签的情况
		g.Log().Debug(ctx, "模板没有标签数据")
	}

	// 根据CategoryId查询分类信息
	if mbTemplate.CategoryId > 0 {
		categoryResult, err := dao.MbCategories.Ctx(ctx).
			Where("id", mbTemplate.CategoryId).
			One()
		if err != nil {
			return nil, err
		}

		if !categoryResult.IsEmpty() {
			category := model.EnHrefItem{}
			if err = gconv.Scan(categoryResult, &category); err != nil {
				return nil, err
			}

			// 设置详情对象的分类
			detail.FenLei = category
		}
	}

	return detail, nil
}

// GetRelatedTemplates 获取相关模板
func (s *sTemplate) GetRelatedTemplates(ctx context.Context, template *model.MBDetail, limit int) ([]model.MbTemplateItem, error) {
	// 构建查询条件
	query := dao.MbTemplates.Ctx(ctx).Where("id <> ?", template.Id)

	// 根据分类匹配相关模板
	if template.FenLei.En != "" {
		// 先根据分类英文名查询分类ID
		categoryObj, err := dao.MbCategories.Ctx(ctx).Where("en", template.FenLei.En).One()
		if err == nil && !categoryObj.IsEmpty() {
			var category entity.MbCategories
			if err = gconv.Scan(categoryObj, &category); err == nil && category.Id > 0 {
				query = query.Where("category_id", category.Id)
			}
		}
	}

	// 如果有标签，尝试根据标签匹配相关模板
	if len(template.Tags) > 0 {
		// 获取标签IDs
		tagIds := make([]int, 0)
		for _, tag := range template.Tags {
			if tag.En != "" {
				// 查询标签ID
				tagObj, err := dao.MbTags.Ctx(ctx).Where("en", tag.En).One()
				if err == nil && !tagObj.IsEmpty() {
					var t entity.MbTags
					if err = gconv.Scan(tagObj, &t); err == nil {
						tagIds = append(tagIds, t.Id)
					}
				}
			}
		}

		// 如果找到匹配的标签ID，通过标签关联查询
		if len(tagIds) > 0 {
			// 创建OR条件组合查询
			for _, tagId := range tagIds {
				query = query.WhereOrLike("tags", "%"+strconv.Itoa(tagId)+"%")
			}
		}
	}

	// 执行查询
	result, err := query.
		Limit(limit).
		OrderDesc("updated").
		All()
	if err != nil {
		return nil, err
	}

	// 转换为模板列表
	templates := make([]model.MbTemplateItem, 0)
	if err = gconv.Scan(result, &templates); err != nil {
		return nil, err
	}

	return templates, nil
}

func (s *sTemplate) SaveByMBDetail(ctx context.Context, mBDetail *model.MBDetail) error {

	var err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {

		// 保存种类
		category_id, err := s.SaveCategory(&mBDetail.FenLei, ctx)
		if err != nil {
			return err
		}

		// 保存Tag标签
		tags, err := s.SaveTags(&mBDetail.Tags, &tx)
		if err != nil {
			return err
		}

		// 保存模板数据
		var template model.MbTemplateItem = s.getTemplateFrom(mBDetail)
		template.CategoryId = category_id
		template.Tags = tags
		err = s.SaveTemplate(&template, &tx)

		return err
	})

	return err
}

func (s *sTemplate) SaveTemplate(template *model.MbTemplateItem, tx *gdb.TX) (err error) {
	var existTemplate entity.MbTemplates
	// 将模板对象转换为数据库实体对象
	var mbTemplate = &do.MbTemplates{
		SId:        template.SId,
		Title:      template.Title,
		Thumb:      template.Thumb,
		Images:     template.Images,
		Preview:    template.Preview,
		FileSize:   template.FileSize,
		Desc:       template.Desc,
		Updated:    template.Updated,
		Origin:     template.Origin,
		CategoryId: template.CategoryId,
		Download:   template.Download,
		Tags:       template.Tags,
	}
	// 使用SId字段查询是否存在
	err = (*tx).Model(new(entity.MbTemplates)).Where("s_id", mbTemplate.SId).Scan(&existTemplate)
	if err != nil {
		// 不存在则插入新记录
		_, err = (*tx).Model(new(entity.MbTemplates)).Data(mbTemplate).Insert()
	} else {
		// 存在则更新记录，使用数据库ID作为条件
		_, err = (*tx).Model(new(entity.MbTemplates)).Where("id", existTemplate.Id).Data(mbTemplate).Update()
	}
	return
}

func (s *sTemplate) getTemplateFrom(mBDetail *model.MBDetail) model.MbTemplateItem {
	// 将图片数组编码为JSON
	imagesJson, err := json.Marshal(mBDetail.Images)
	if err != nil {
		g.Log().Error(context.Background(), "图片转换JSON失败:", err)
		imagesJson = []byte("[]") // 出错时使用空数组
	}

	var template = model.MbTemplateItem{
		MbTemplates: entity.MbTemplates{
			Id:       0, // 自增ID，插入时不需要指定
			SId:      mBDetail.SId,
			Title:    mBDetail.Title,
			Thumb:    mBDetail.Thumb,
			Images:   string(imagesJson), // 将[]byte转换为string
			Preview:  mBDetail.Preview,
			FileSize: mBDetail.FileSize,
			Desc:     mBDetail.Desc,
			Updated:  gtime.New(mBDetail.Updated + ":00"),
			Origin:   mBDetail.Origin,
		},
		SId:      mBDetail.SId,
		Images:   mBDetail.Images,
		Download: mBDetail.Download,
		Tags:     []int{},
	}
	return template
}

func (s *sTemplate) SaveTags(tags *[]model.EnHrefItem, tx *gdb.TX) (ids []int, err error) {
	for _, item := range *tags {
		var obj entity.MbTags
		var err = (*tx).Model(new(do.MbTags)).Where("en", item.En).Scan(&obj)
		if err == nil {
			ids = append(ids, obj.Id)
		} else {
			var obj = &do.MbTags{
				Title:  item.Title,
				En:     item.En,
				Origin: item.Url,
				IsShow: 0, // 默认不显示
			}
			id, err := (*tx).Model(new(do.MbTags)).Data(obj).InsertAndGetId()
			if err != nil {
				return nil, err
			}
			ids = append(ids, gconv.Int(id))
		}
	}
	return ids, nil
}

func (s *sTemplate) SaveCategory(item *model.EnHrefItem, ctx context.Context) (id int, err error) {
	// 在保存时根据英文名查询分类
	var category entity.MbCategories
	err = dao.MbCategories.Ctx(ctx).Where("en", item.En).Scan(&category)

	if err == nil {
		return category.Id, err
	} else {
		var category2 = &do.MbCategories{
			Title:  item.Title,
			En:     item.En,
			Origin: item.Url,
			IsShow: 1, // 默认显示
		}
		id, err := dao.MbCategories.Ctx(ctx).Data(category2).InsertAndGetId()
		return gconv.Int(id), err
	}
}
